package model;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
 * The MaterialList class contains a Map of Materials and offers methods to alter this MaterialList and calculate new MaterialLists.
 * 
 * @author hfi411pi
 *
 */
public class MaterialList {

	private final Map<String, QuantifiedComponent> materials;
	public Map<String, QuantifiedComponent> getMaterials(){
		return this.materials;
	}
	
	/**
	 * Factory method for creating an empty MaterialList.
	 * @return the created MaterialList.
	 */
	public static MaterialList create(){
		return new MaterialList();
	}
	
	/**
	 * Default Constructor of MaterialList.
	 */
	private MaterialList(){
		this.materials = new HashMap<String, QuantifiedComponent>();
	}
	
	/**
	 * Multiplies each component of this MaterialList with the provided factor 
	 * and returns the result.
	 * Does not alter this MaterialList.
	 * @param factor is the factor each component will be multiplied with.
	 * @return the resulting MaterialList.
	 */
	public MaterialList multiply(final int factor){
		final MaterialList result = MaterialList.create();
		final Iterator<QuantifiedComponent> i = this.getMaterials().values().iterator();
		while(i.hasNext()){
			final QuantifiedComponent current = i.next();
			result.add(QuantifiedComponent.createQuantifiedComponent(current.getQuantity() * factor, current.getComponent()));
		}
		return result;
	}
	
	/**
	 * Merges two MaterialList.
	 * Neither MaterialList is altered by this method.
	 * @param	secondList is the second MaterialList to merge in the resulting MaterialList.
	 * @return	the new MaterialMap with all components of this MaterialList and all
	 * 			components provided in the secondList parameter.
	 */
	public MaterialList merge(final MaterialList secondList){
		final MaterialList result = this.copy();
		final Iterator<QuantifiedComponent> secondIterator = secondList.getMaterials().values().iterator();
		while(secondIterator.hasNext()){
			final QuantifiedComponent current = secondIterator.next();
			result.add(QuantifiedComponent.createQuantifiedComponent(current.getQuantity(), current.getComponent()));
		}
		return result;
	}

	/**
	 * Adds a QuantifiedComponent to this MaterialMap.
	 * If the Component of the QuantifiedComponent is already in this MaterialList the
	 * Quantity of the existing QuantifiedComponent is increased by the Quantity of the newComponent.
	 * If the Component of the QuantifiedComponent is not in this MaterialList the
	 * newComponent is put in this MaterialList.
	 * Alters this MaterialList.
	 * @param newComponent is the QuantifiedComponent containing a Material to add.
	 */
	public void add(final QuantifiedComponent newComponent){
		if(this.getMaterials().containsKey(newComponent.getComponent().getName())){
			final QuantifiedComponent component = this.getMaterials().get(newComponent.getComponent().getName());
			component.setQuantity(component.getQuantity() + newComponent.getQuantity());
		} else {
			this.getMaterials().put(newComponent.getName(), newComponent);
		}
	}
	
	/**
	 * Provides a copy of this MaterialList.
	 * @return a copy of this MaterialList.
	 */
	private MaterialList copy() {
		final MaterialList result = MaterialList.create();
		final Iterator<QuantifiedComponent> firstIterator = this.getMaterials().values().iterator();
		while(firstIterator.hasNext()){
			final QuantifiedComponent current = firstIterator.next();
			result.add(QuantifiedComponent.createQuantifiedComponent(current.getQuantity(), current.getComponent()));
		}
		return result;
	}	
}